/*
#include <serial.h>
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-11-19     Eywen       the first version
 */

#include "serial.h"
#include <rtthread.h>
#include <stdarg.h>
#include <string.h>
#include "files.h"

#define GCODE_REPY_OK_STR               "ok\r\n"
#define GCODE_REPY_ERR_STR              "gcode err\r\n"
#define GCODE_STR_MAX_LEN               256

#define SERIAL_UART_NAME                "uart2"      /* 串口设备名称， RX: PIN1 TX: PIN2 */
static rt_device_t serial_gcode;
/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断，调用此回调函数，然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

/* 串口接收处理线程，可以域解析每条gcode */
static void serial_thread_entry(void *parameter)
{
    extern int s_last_select_file_idx;
    char str[GCODE_STR_MAX_LEN];
    char recv[GCODE_STR_MAX_LEN];
    char ch;
    int cnt = 0;
    int recv_cnt;
    extern bool g_print_flag;
    int select_file_idx;
    int err_times;
    while (1){
            /* 屏幕按下了打印按钮，且选择了文件 */
            if((g_print_flag == true) && (s_last_select_file_idx > 0)){
                select_file_idx = s_last_select_file_idx;
                /* 循环读取一行命令 */
                while(get_line_gcoode_from_file(get_select_file_name(select_file_idx - 1), str) > 0){
                    err_times = 0;
                    while(err_times < 1000){
                        /* 上次由于超时或从机忙导致失败，则等待一会儿再发送 */
                        if(err_times > 0){
                            debug_info("try times: %d", err_times);
                            rt_thread_mdelay(10);
                        }
                        /* 发送命令给gcode 串口 */
                        serial_echo(str);
                        recv_cnt = 0;
                        /* 循环查询回复 "OK\r\n" */
                        ch = 0;
                        while(ch != '\n'){
                            /* 超时1000ms, 则认为接收完整一串gcode回复失败 */
                            if(RT_EOK != rt_sem_take(&rx_sem, 1000)){
                                if(recv_cnt != 0){
                                    recv_cnt = 0;
                                    rt_thread_mdelay(5);
                                    /* 删去完剩下的所有字符 */
                                    while(rt_device_read(serial_gcode, -1, &ch, 1) == 1){
                                        /* 等待一会儿接收下一个字符 */
                                        rt_thread_mdelay(5);
                                    }
                                    /* 接收失败 */
                                    debug_info("recv timeout");
                                    recv[recv_cnt] = '\0';
                                    break;
                                }
                            }

                            /* 等待从串口读取一个字节的数据 */
                            if (rt_device_read(serial_gcode, -1, &ch, 1) == 1){
                                recv[recv_cnt] = '\0';
                                break;
                            }
                            recv[recv_cnt++] = ch;
                        }
                        recv[recv_cnt] = '\0';
                        /* 接收正确 */
                        if((ch == '\n') && (strcmp(recv, GCODE_REPY_OK_STR) == 0)){
                            break;
                        }
                        ++err_times;
                    }
                    /* 单条gcode命令重复发送了1000次，则不再发送，结束打印 */
                    if(err_times >= 1000){
                        debug_error("gcode send err");
                        break;
                    }
                }
                /* 打印标志去使能，防止继续重复打印 */
                g_print_flag = false;
            }
        debug_info("serial_thread_entry!");
        //serial_echo(GCODE_REPY_OK_STR);
        rt_thread_mdelay(10);
    }
}

bool serial_thread_init(const char *serial_name)
{
    rt_err_t ret = RT_EOK;
    char *uart_name;
    if(serial_name == NULL){
        uart_name = (char *)SERIAL_UART_NAME;
    }
    else{
        uart_name = (char *)serial_name;
    }

    /* 查找串口设备 */
    serial_gcode = rt_device_find(uart_name);
    if (!serial_gcode){
        debug_warn("find %s failed!\n", uart_name);
        return RT_ERROR;
    }
    else{
        debug_info("find ok");
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

    /* 设置串口速率为115200 */
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = 115200;
    rt_device_control(serial_gcode, RT_DEVICE_CTRL_CONFIG, &config);

    /* 以读写及中断接收方式打开串口设备 */
    rt_device_open(serial_gcode, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
    rt_device_set_rx_indicate(serial_gcode, uart_input);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 2048, 10, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL){
        rt_thread_startup(thread);
    }
    else{
        ret = RT_ERROR;
    }

    return ret;
}


bool serial_echo_string(char *str)
{
    return rt_device_write(serial_gcode, 0, str, strlen(str));
}

bool serial_echo(const char *format, ...)
{
    va_list args;
    int n;
    static char debug_buff[254];
    va_start(args, format);
    n = rt_vsnprintf(debug_buff, 254, format, args);
    va_end(args);
    rt_device_write(serial_gcode, 0, debug_buff, n);
}
